﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;

namespace InvadersEx01
{
    public class Enemies
    {
        private enum eMovingDirection
        {
            Left,
            Right
        }

        private const float k_EnemyWidth = 32;
        private const float k_EnemyHeight = 32;
        private const float k_OffsetFromTop = k_EnemyHeight * 2;
        private const float k_DistanceBetweenEnemies = 10;
        private const float k_EnemiesWidth = (k_EnemyWidth * 7) + (k_DistanceBetweenEnemies * 6);
        private const float k_EnemiesHeight = (k_EnemyHeight * 5) + (k_DistanceBetweenEnemies * 4);

        private float m_MoveInterval = (float)TimeSpan.FromSeconds(0.5f).TotalSeconds;
        private float m_TimeToNextMove;
        private float m_ScreenWidth;
        private float m_ScreenHeight;
        private bool m_ReachedBottom;
        private Vector2 m_Position;
        private eMovingDirection m_MovingDirection;

        public List<Enemy> EnemiesList { get; private set; }

        public Enemies(float i_ScreenWidth, float i_ScreenHeight)
        {
            EnemiesList = new List<Enemy>();
            m_Position = new Vector2(0, k_OffsetFromTop);
            m_MovingDirection = eMovingDirection.Right;
            m_ReachedBottom = false;
            m_ScreenWidth = i_ScreenWidth;
            m_ScreenHeight = i_ScreenHeight;

            for (int i = 0; i < 5; i++)
            {
                for (int j = 0; j < 7; j++)
                {
                    if (i < 2)
                    {
                        EnemiesList.Add(new Enemy(new Vector2(m_Position.X + (j * (k_EnemyWidth + k_DistanceBetweenEnemies)), m_Position.Y + (i * (k_EnemyHeight + k_DistanceBetweenEnemies))), eEnemyType.Enemy1));
                    }
                    else if (i < 4)
                    {
                        EnemiesList.Add(new Enemy(new Vector2(m_Position.X + (j * (k_EnemyWidth + k_DistanceBetweenEnemies)), m_Position.Y + (i * (k_EnemyHeight + k_DistanceBetweenEnemies))), eEnemyType.Enemy2));
                    }
                    else
                    {
                        EnemiesList.Add(new Enemy(new Vector2(m_Position.X + (j * (k_EnemyWidth + k_DistanceBetweenEnemies)), m_Position.Y + (i * (k_EnemyHeight + k_DistanceBetweenEnemies))), eEnemyType.Enemy3));
                    }
                }
            }

            m_TimeToNextMove = m_MoveInterval;
        }

        /// <summary>
        /// Moves all the enemies according to the time passes since previous move.
        /// </summary>
        /// <param name="totalSecondsPassed">Time passed since previous move.</param>
        /// <returns>True if the enemies reached the bottom of the screen.</returns>
        public bool MoveEnemies(float totalSecondsPassed)
        {
            bool reachedBottom = false;

            m_TimeToNextMove -= totalSecondsPassed;

            if (m_TimeToNextMove <= 0)
            {
                m_TimeToNextMove = m_MoveInterval;

                switch (m_MovingDirection)
                {
                    case eMovingDirection.Right:
                        if (m_Position.X + (k_EnemyWidth / 2) + k_EnemiesWidth <= m_ScreenWidth)
                        {
                            moveRight();
                        }
                        else
                        {
                            reachedBottom = reachEdgeAction();
                        }

                        break;
                    case eMovingDirection.Left:
                        if (m_Position.X - (k_EnemyWidth / 2) >= 0)
                        {
                            moveLeft();
                        }
                        else
                        {
                            reachedBottom = reachEdgeAction();
                        }
                        
                        break;
                }
            }

            return reachedBottom;
        }

        private bool reachEdgeAction()
        {
            bool reachedBottom = false;

            if (m_Position.Y + k_EnemyHeight + k_EnemiesHeight > m_ScreenHeight && !m_ReachedBottom)
            {
                moveDown();
                m_ReachedBottom = reachedBottom = true;
            }
            else
            {
                if (!m_ReachedBottom)
                {
                    moveDown();
                    toggleMovingDirection();
                }
            }

            return reachedBottom;
        }

        private void toggleMovingDirection()
        {
            if (m_MovingDirection == eMovingDirection.Left)
            {
                m_MovingDirection = eMovingDirection.Right;
            }
            else
            {
                m_MovingDirection = eMovingDirection.Left;
            }
        }

        private void moveRight()
        {
            m_Position.X += k_EnemyWidth / 2;

            foreach (Enemy enemy in EnemiesList)
            {
                Vector2 newPosition = new Vector2(
                    enemy.Position.X + (k_EnemyWidth / 2),
                    enemy.Position.Y);

                enemy.Position = newPosition;
            }
        }

        private void moveLeft()
        {
            m_Position.X -= k_EnemyWidth / 2;

            foreach (Enemy enemy in EnemiesList)
            {
                Vector2 newPosition = new Vector2(
                    enemy.Position.X - (k_EnemyWidth / 2),
                    enemy.Position.Y);

                enemy.Position = newPosition;
            }
        }

        private void moveDown()
        {
            m_Position.Y += k_EnemyHeight / 2;

            foreach (Enemy enemy in EnemiesList)
            {
                Vector2 newPosition = new Vector2(
                    enemy.Position.X,
                    enemy.Position.Y + (k_EnemyHeight / 2));

                enemy.Position = newPosition;
            }

            m_MoveInterval -= 0.07f * m_MoveInterval;
        }
    }
}